package com.superhelper.app.utils;

import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import java.util.List;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import com.pingplusplus.model.Charge;
import com.pingplusplus.model.Event;
import com.pingplusplus.model.EventData;
import com.pingplusplus.model.PingppObject;
import com.pingplusplus.model.Webhooks;

public class WebHooksVerify {

    /**
     * 验证webhooks 签名，仅供参考
     * 
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {

        // boolean result = verifyData(getByteFromFile(eventPath, false),
        // getByteFromFile(signPath, true), getPubKey());
        // System.out.println("验签结果：" + result);
        String sign = "XU4VEFx2KBvn6VKFpstrhRigfdm0BDN+Z+7RSCTMw10CdQ6voeI4UeXw/jTZATv4ZY29w4Zob4g3lip/WSDBrF9odMpSUjhWOSh3VJVf8HAnnXiLl2V3u2RP7tYJBXue5YAfNrvsxFWZ7ZjUsqiqC0ckzA5drCru73igBzwRYS9NVnwlhZAYZ5e/lkh1H95yPOYKOoUk0O2p2x+78HNntSquDLyQcSQrXyrlqaVKSKRp7ZkIMcMBUD1l2Nrb2YX9MUXOBmEc6IoB5mr1IlJ0zNtc8izjnJTPBfFps9NGwghp04ovxnnrOG8pnrAabG7n5PDG2Y3d3IdfIFVRQetVIA==";
        String evnt = "{\"id\":\"evt_ugB6x3K43D16wXCcqbplWAJo\",\"created\":1440407501,\"livemode\":false,\"type\":\"charge.succeeded\",\"data\":{\"object\":{\"id\":\"ch_Xsr7u35O3m1Gw4ed2ODmi4Lw\",\"object\":\"charge\",\"created\":1440407501,\"livemode\":true,\"paid\":true,\"refunded\":false,\"app\":\"app_urj1WLzvzfTK0OuL\",\"channel\":\"upacp\",\"order_no\":\"123456789\",\"client_ip\":\"127.0.0.1\",\"amount\":100,\"amount_settle\":0,\"currency\":\"cny\",\"subject\":\"Your Subject\",\"body\":\"Your Body\",\"extra\":{},\"time_paid\":1440407501,\"time_expire\":1440407501,\"time_settle\":null,\"transaction_no\":\"1224524301201505066067849274\",\"refunds\":{\"object\":\"list\",\"url\":\"/v1/charges/ch_Xsr7u35O3m1Gw4ed2ODmi4Lw/refunds\",\"has_more\":false,\"data\":[]},\"amount_refunded\":0,\"failure_code\":null,\"failure_msg\":null,\"metadata\":{},\"credential\":{},\"description\":null}},\"object\":\"event\",\"pending_webhooks\":0,\"request\":\"iar_qH4y1KbTy5eLGm1uHSTS00s\"}";
        System.out.println(verify(evnt, sign));

        Event event = Webhooks.eventParse(evnt);

        EventData data = event.getData();
        PingppObject obj = data.getObject();
        if (obj instanceof Charge) {

            Charge charge = (Charge) obj;
            String dealNo = charge.getOrderNo();
            Long payt = charge.getTimePaid();
            String payDealNo = charge.getTransactionNo();
            Date payTime = new Date(payt * 1000);

            System.out.println(dealNo);
            System.out.println(payDealNo);
            System.out.println(payTime);

        }
    }

    public static boolean verify(String event, String sign) throws InvalidKeyException, NoSuchAlgorithmException,
            SignatureException, UnsupportedEncodingException, Exception {
        if (pk == null) {
            pk = getPubKey();
        }
        boolean result = verifyData(event.getBytes("utf-8"), getByteFromStr(sign, true), pk);
        return result;
    }

    /**
     * 读取文件,部署web程序的时候，签名和验签内容需要从request中获得
     * 
     * @param file
     * @param base64
     * @return
     * @throws Exception
     */
    public static byte[] getByteFromStr(String str, boolean base64) throws Exception {
        if (base64) {
            return Base64.decodeBase64(str);
        }
        return str.getBytes("utf-8");
    }

    private static PublicKey pk = null;

    /**
     * 获得公钥
     * 
     * @return
     * @throws Exception
     */
    public static PublicKey getPubKey() throws Exception {
        // read key bytes
        List<String> lines = IOUtils.readLines(new InputStreamReader(WebHooksVerify.class.getClassLoader()
                .getResourceAsStream("pingpp-pub.key"), "utf-8"));
        String pubKey = StringUtils.join(lines, System.getProperty("line.separator", "\n"));
        pubKey = pubKey.replaceAll("(-+BEGIN PUBLIC KEY-+\\r?\\n|-+END PUBLIC KEY-+\\r?\\n?)", "");

        byte[] keyBytes = Base64.decodeBase64(pubKey);

        // generate public key
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(spec);
        return publicKey;
    }

    /**
     * 验证签名
     * 
     * @param data
     * @param sigBytes
     * @param publicKey
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws SignatureException
     */
    public static boolean verifyData(byte[] data, byte[] sigBytes, PublicKey publicKey)
            throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(publicKey);
        signature.update(data);
        return signature.verify(sigBytes);
    }

}
